﻿// This source is subject to Microsoft Public License (Ms-PL).
// Please see http://taskcardcreator.codeplex.com for details.
// All other rights reserved.

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Interop;
using System.Windows.Xps.Packaging;
using MSFforAgileSoftwareDevelopmentv50;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using MicrosoftVisualStudioScrum10;
using WorkItemReportInterface;
using MessageBox = System.Windows.MessageBox;

namespace TaskCardCreator
{
  /// <summary>
  /// Interaction logic for MainWindow.xaml
  /// </summary>
  public partial class MainWindow : Window, System.Windows.Forms.IWin32Window
  {
    private ProjectInfo projInfo;
    private WorkItemStore workItemStoreService;
    private WorkItemTypeCollection wiTypes;
    private BackgroundWorker worker;
    private string pendingRequest = string.Empty;

    public ObservableCollection<WorkItem> WorkItems { get; set; }

    public MainWindow()
    {
      WorkItems = new ObservableCollection<WorkItem>();

      InitializeComponent();

      listView.DataContext = this;
      queries.SelectionChanged += queries_SelectionChanged;
    }

    private void selectProjectButton_Click(object sender, RoutedEventArgs e)
    {
      using (TeamProjectPicker tpp = new TeamProjectPicker(TeamProjectPickerMode.SingleProject, false))
      {
        DialogResult result = tpp.ShowDialog(this);

        if (result == System.Windows.Forms.DialogResult.OK)
        {
          projInfo = tpp.SelectedProjects[0];
          workItemStoreService = tpp.SelectedTeamProjectCollection.GetService<WorkItemStore>();
          foreach (Project project in workItemStoreService.Projects)
          {
              if (project.Name == projInfo.Name)
              {
                  wiTypes = project.WorkItemTypes;
                  break;
              }
              wiTypes = null;
          }
          queries.BuildQueryTree(workItemStoreService.Projects[tpp.SelectedProjects[0].Name].QueryHierarchy, projInfo.Name);
        }
      }
    }

    private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
      var newWorkItems = new ObservableCollection<WorkItem>();

      var q = new Query(workItemStoreService, (string)e.Argument);
      if (q.IsLinkQuery)
      {
        var queryResults = q.RunLinkQuery();
        foreach (WorkItemLinkInfo i in queryResults)
        {
          var wi = workItemStoreService.GetWorkItem(i.TargetId);
          newWorkItems.Add(wi);
        }
      }
      else
      {
        var queryResults = q.RunQuery();
        foreach (WorkItem workitem in queryResults)
        {
          newWorkItems.Add(workitem);
        }
      }
      e.Result = newWorkItems;
    }

    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
      if (e.Cancelled == true)
      {
      }
      else if (e.Error != null)
      {
        MessageBox.Show(string.Format("Error: {0}", e.Error.Message));
      }
      else
      {
        var newWorkItems = (ObservableCollection<WorkItem>)e.Result;

        foreach (var item in newWorkItems)
        {
          WorkItems.Add(item);
        }
        
        listView.SelectAll();
      }
      progress.Visibility = Visibility.Collapsed;

      // Any pending requests?
      if (pendingRequest != string.Empty)
      {
        queries_SelectionChanged((string) pendingRequest.Clone());
        pendingRequest = string.Empty;
      }
    }

    void queries_SelectionChanged(string queryString)
    {
      progress.Visibility = Visibility.Visible;

      WorkItems.Clear();

      if (worker == null)
      {
        worker = new BackgroundWorker();
        worker.WorkerSupportsCancellation = false;
        worker.WorkerReportsProgress = false;

        worker.DoWork += bw_DoWork;
        worker.RunWorkerCompleted += bw_RunWorkerCompleted;
      }

      if (worker.IsBusy)
      {
        pendingRequest = queryString;
      }
      else
      {
        worker.RunWorkerAsync(queryString);
      }
    }

    private enum ProjectTypes
    {
      MicrosoftVisualStudioScrum10,
      MSFforAgileSoftwareDevelopmentv50,
      UpgradedProcessTemplate,
      Unknown
    }

    /// <summary>
    /// Try to detect process template. This is done by looking at specific work item types
    /// </summary>
    /// <returns>Project type</returns>
    private ProjectTypes ProjectType()
    {
      if (wiTypes == null)
        return ProjectTypes.Unknown;

      if (wiTypes.Count == 0)
        return ProjectTypes.Unknown;

      //An MSF Agile v4.0 process template can be upgraded to MSF Agile v5.0, this is messy and so it is unsupported.
      if (wiTypes.Contains("User Story") == true && wiTypes.Contains("Scenario") == true)
          return ProjectTypes.UpgradedProcessTemplate;

      // Only the Scrum process template has this type
      if (wiTypes.Contains("Product Backlog Item") == true)
        return ProjectTypes.MicrosoftVisualStudioScrum10;

      // Only the MSF for Agile process template has this type
      if (wiTypes.Contains("User Story") == true)
        return ProjectTypes.MSFforAgileSoftwareDevelopmentv50;

      return ProjectTypes.Unknown;
    }

    private void generateReport_Click(object sender, RoutedEventArgs e)
    {
      if (projInfo == null)
        return;

      if (worker != null)
      {
        if (worker.IsBusy)
        {
          MessageBox.Show("Unable to generate report while loading work items!", "Error");
          return;
        }
      }

      // Create report
      IWorkItemReport reportTemplate = null;
      switch (ProjectType())
      {
        case ProjectTypes.MicrosoftVisualStudioScrum10:
          reportTemplate = new MicrosoftVisualStudioScrum10Template();
          break;
        case ProjectTypes.MSFforAgileSoftwareDevelopmentv50:
          reportTemplate = new MSFforAgileSoftwareDevelopmentv50Template();
          break;
        case ProjectTypes.UpgradedProcessTemplate:
          MessageBox.Show("The current project is using an upgraded process template." +
                          "\nThis process template is not supported." +
                          "\n" +
                          "\nSupported process templates:" +
                          "\nMicrosoft Visual Studio Scrum 1.0" +
                          "\nMSF for Agile Software Development v5.0", "Error");
          return;
        default:
          MessageBox.Show("Supported process templates:\nMicrosoft Visual Studio Scrum 1.0\nMSF for Agile Software Development v5.0", "Error");
          return;
      }

      var ms = new MemoryStream();
      var pkg = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite);
      string pack = string.Format("pack://{0}.xps", Guid.NewGuid());
      PackageStore.AddPackage(new Uri(pack), pkg);
      var document = new XpsDocument(pkg, CompressionOption.SuperFast, pack);
      var data = listView.SelectedItems.Cast<WorkItem>().ToList();
      var report = reportTemplate.Create(data);
      var writer = XpsDocument.CreateXpsDocumentWriter(document);
      writer.Write(report.DocumentPaginator);

      // Create tab
      var tab = new TabItem {Header = "Report @ " + DateTime.Now.ToLongTimeString()};
      var doc = new DocumentViewer {Document = document.GetFixedDocumentSequence()};
      doc.FitToMaxPagesAcross(1);
      tab.Content = doc;
      tabControl.Items.Insert(1, tab);
      tabControl.SelectedItem = tab;
    }

    private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
    {
      System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(e.Uri.AbsoluteUri));
      e.Handled = true;
    }

    public IntPtr Handle
    {
      get
      {
        return ((HwndSource)PresentationSource.FromVisual(this)).Handle;
      }
    }

    private void CheckForUpdatesButton_Click(object sender, RoutedEventArgs e)
    {
      System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(@"http://taskcardcreator.codeplex.com/releases"));
    }
  }
}
